package com.material.fish;

import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.PointF;
import android.graphics.drawable.Drawable;
import android.view.animation.LinearInterpolator;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

/**
 * @author linzhi <a href="mailto:zhilinchn@126.com">Contact me.</a>
 * @version 1.0
 * @since 2021/10/22 10:17 下午
 */
public class FishDrawable extends Drawable {

  private static final int BODY_ALPHA = 160;
  private Paint mPaint;

  private Path mPath;

  private final static int OTHER_ALPHA = 110;

  //重心
  private PointF middlePoint;

  //鱼的主要朝向角度
  private float fishMainAngle = 90;

  private float frequency = 1f ;

  // <editor-fold defaultstate="collapsed" desc="鱼长度值">
  //鱼头
  public static final float HEAD_RADIUS = 50;
  //鱼身长度
  private float BODY_LENGTH = HEAD_RADIUS * 3.2f;
  //寻找鱼鳍起始点坐标的线长
  private float FIND_FINS_LENGTH = 0.9f * HEAD_RADIUS;
  //鱼鳍长度
  private float FINS_LENGTH = 1.3f * HEAD_RADIUS;
  // 大圆的半径
  private float BIG_CIRCLE_RADIUS = 0.7f * HEAD_RADIUS;
  // 中圆的半径
  private float MIDDLE_CIRCLE_RADIUS = 0.6f * BIG_CIRCLE_RADIUS;
  // 小圆半径
  private float SMALL_CIRCLE_RADIUS = 0.4f * MIDDLE_CIRCLE_RADIUS;
  // --寻找尾部中圆圆心的线长
  private final float FIND_MIDDLE_CIRCLE_LENGTH = BIG_CIRCLE_RADIUS * (0.6f + 1);
  // --寻找尾部小圆圆心的线长
  private final float FIND_SMALL_CIRCLE_LENGTH = MIDDLE_CIRCLE_RADIUS * (0.4f + 2.7f);
  // --寻找大三角形底边中心点的线长
  private final float FIND_TRIANGLE_LENGTH = MIDDLE_CIRCLE_RADIUS * 2.7f;
  private float currentValue;
  private PointF fishHeadPoint;

  // </editor-fold>
  public FishDrawable() {
    init();
  }

  private void init() {
    mPaint = new Paint();
    mPath = new Path();
    mPaint.setStyle(Paint.Style.FILL);
    mPaint.setAntiAlias(true);
    mPaint.setDither(true);
    mPaint.setARGB(OTHER_ALPHA, 244, 92, 71);
    middlePoint = new PointF(4.19f * HEAD_RADIUS, 4.19f * HEAD_RADIUS);

    ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 3600f);
    valueAnimator.setDuration(15 * 1000);

    valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
    valueAnimator.setRepeatMode(ValueAnimator.RESTART);
    valueAnimator.setInterpolator(new LinearInterpolator());
    valueAnimator.start();
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
      @Override public void onAnimationUpdate(ValueAnimator animation) {
        currentValue = (float) animation.getAnimatedValue();
        invalidateSelf();
      }
    });
  }

  @Override public void draw(@NonNull Canvas canvas) {

    float fishAngle = (float) (fishMainAngle + Math.sin(Math.toRadians(currentValue/*摆动周期*/ * frequency) /*[-1,1]*/)* 10/*摆动角度*/);
    //鱼头
    fishHeadPoint = calculatePoint(middlePoint, BODY_LENGTH / 2, fishAngle);
    canvas.drawCircle(fishHeadPoint.x, fishHeadPoint.y, HEAD_RADIUS, mPaint);

    //鱼鳍
    PointF rightFinsPoint = calculatePoint(fishHeadPoint, FIND_FINS_LENGTH, fishAngle - 110);
    makeFins(canvas, rightFinsPoint, fishAngle, true);

    PointF leftFinsPoint = calculatePoint(fishHeadPoint, FIND_FINS_LENGTH, fishAngle + 110);
    makeFins(canvas, leftFinsPoint, fishAngle, false);

    // 节肢1
    PointF bodyBottomCenterPoint = calculatePoint(fishHeadPoint, BODY_LENGTH, fishAngle - 180);
    PointF middleCenterPoint =
        makeSegment(canvas, bodyBottomCenterPoint, BIG_CIRCLE_RADIUS, MIDDLE_CIRCLE_RADIUS,
            FIND_MIDDLE_CIRCLE_LENGTH, fishAngle, true);

    // 节肢2
    makeSegment(canvas, middleCenterPoint, MIDDLE_CIRCLE_RADIUS, SMALL_CIRCLE_RADIUS,
        FIND_SMALL_CIRCLE_LENGTH, fishAngle, false);

    float findEdgeLength =
        (float) Math.abs(Math.sin(Math.toRadians(currentValue * 1.5 * frequency)) * BIG_CIRCLE_RADIUS);

    //尾巴
    makeTriangle(canvas, middleCenterPoint, FIND_TRIANGLE_LENGTH, findEdgeLength, fishAngle);
    makeTriangle(canvas, middleCenterPoint, FIND_TRIANGLE_LENGTH - 10, findEdgeLength - 20,
        fishAngle);

    //身体
    makeBody(canvas, fishHeadPoint, bodyBottomCenterPoint, fishAngle);

  }

  private void makeBody(Canvas canvas, PointF headPoint, PointF bodyBottomCenterPoint,
      float fishAngle) {
    PointF topLeftPoint = calculatePoint(headPoint, HEAD_RADIUS, fishAngle + 90);
    PointF topRightPoint = calculatePoint(headPoint, HEAD_RADIUS, fishAngle - 90);
    PointF bottomLeftPoint =
        calculatePoint(bodyBottomCenterPoint, BIG_CIRCLE_RADIUS, fishAngle + 90);
    PointF bottomRightPoint =
        calculatePoint(bodyBottomCenterPoint, BIG_CIRCLE_RADIUS, fishAngle - 90);

    PointF controlLeft = calculatePoint(headPoint, BODY_LENGTH * 0.56f, fishAngle + 130);
    PointF controlRight = calculatePoint(headPoint, BODY_LENGTH * 0.56f, fishAngle - 130);

    mPath.reset();
    mPath.moveTo(topLeftPoint.x, topLeftPoint.y);
    mPath.quadTo(controlLeft.x, controlLeft.y, bottomLeftPoint.x, bottomLeftPoint.y);
    mPath.lineTo(bottomRightPoint.x, bottomRightPoint.y);
    mPath.quadTo(controlRight.x, controlRight.y, topRightPoint.x, topRightPoint.y);
    mPaint.setAlpha(BODY_ALPHA);
    canvas.drawPath(mPath, mPaint);
  }

  private void makeTriangle(Canvas canvas, PointF startPoint, float findTriangleLength,
      float bigRadius, float fishAngle) {

    float triangleAngle = (float) (fishAngle + Math.sin(Math.toRadians(currentValue * 1.5 /*满一个周期*/ * frequency)) * 35);
    //三角形底边的中心坐标
    PointF centerPoint = calculatePoint(startPoint, findTriangleLength, triangleAngle - 180);

    PointF leftPoint = calculatePoint(centerPoint, bigRadius, triangleAngle + 90);
    PointF rightPoint = calculatePoint(centerPoint, bigRadius, triangleAngle - 90);

    mPath.reset();
    mPath.moveTo(startPoint.x, startPoint.y);
    mPath.lineTo(leftPoint.x, leftPoint.y);
    mPath.lineTo(rightPoint.x, rightPoint.y);
    mPaint.setAlpha(BODY_ALPHA);
    canvas.drawPath(mPath, mPaint);
  }

  private PointF makeSegment(Canvas canvas, PointF bottomCenterPoint, float bigRadius,
      float middleRadius, float findMiddleCircleLength, float fishAngle, boolean hasBigCircle) {

    float segmentAngle ;
    if (hasBigCircle) {
      segmentAngle = (float) (fishAngle + Math.cos(Math.toRadians(currentValue * 1.5 * frequency)) * 15);
    }else {
      segmentAngle = (float) (fishAngle + Math.sin(Math.toRadians(currentValue * 1.5 * frequency )) * 35);
    }
    // 梯形上底圆的圆心
    PointF upperCenterPoint = calculatePoint(bottomCenterPoint, findMiddleCircleLength,
        segmentAngle - 180);
    // 梯形的四个点
    PointF bottomLeftPoint = calculatePoint(bottomCenterPoint, bigRadius, segmentAngle + 90);
    PointF bottomRightPoint = calculatePoint(bottomCenterPoint, bigRadius, segmentAngle - 90);
    PointF upperLeftPoint = calculatePoint(upperCenterPoint, middleRadius, segmentAngle + 90);
    PointF upperRightPoint = calculatePoint(upperCenterPoint, middleRadius, segmentAngle - 90);

    if (hasBigCircle) {
      //画大圆
      canvas.drawCircle(bottomCenterPoint.x, bottomCenterPoint.y, bigRadius, mPaint);
    }

    //画小圆
    canvas.drawCircle(upperCenterPoint.x, upperCenterPoint.y, middleRadius, mPaint);

    //画梯形
    mPath.reset();
    mPath.moveTo(upperLeftPoint.x, upperLeftPoint.y);
    mPath.lineTo(upperRightPoint.x, upperRightPoint.y);
    mPath.lineTo(bottomRightPoint.x, bottomRightPoint.y);
    mPath.lineTo(bottomLeftPoint.x, bottomLeftPoint.y);
    canvas.drawPath(mPath, mPaint);
    return upperCenterPoint;
  }

  /**
   * 画鱼鳍
   *
   * @param isRight 是否是右鱼鳍
   */
  private void makeFins(Canvas canvas, PointF startPoint, float fishAngle, boolean isRight) {

    float controlAngle;
    if (frequency == 2) {
      controlAngle= (float) (115 + Math.sin(Math.toRadians(currentValue/*摆动周期*/ * frequency *2 ) /*[-1,1]*/)* 10/*摆动角度*/);
    }else {
      controlAngle = 115 ;
    }
    // 鱼鳞的终点
    PointF endPoint = calculatePoint(startPoint, FINS_LENGTH, fishAngle - 180);

    //控制点
    final float calculateAngle = isRight ? fishAngle - controlAngle : fishAngle + controlAngle;
    PointF controlPoint = calculatePoint(startPoint, FINS_LENGTH * 1.8f, calculateAngle);

    // 绘制
    mPath.reset();
    mPath.moveTo(startPoint.x, startPoint.y);
    mPath.quadTo(controlPoint.x, controlPoint.y, endPoint.x, endPoint.y);
    canvas.drawPath(mPath, mPaint);
  }

  /**
   * @param startPoint 起始点坐标
   * @param length 要求的点到起始点的直线距离 -- 线长
   * @param angle 鱼当前的朝向角度
   */
  public PointF calculatePoint(PointF startPoint, float length, float angle) {
    float deltaX = (float) (Math.cos(Math.toRadians(angle)) * length);
    float deltaY = (float) (Math.sin(Math.toRadians(angle - 180)) * length);
    return new PointF(startPoint.x + deltaX, startPoint.y + deltaY);
  }

  @Override public void setAlpha(int alpha) {
    mPaint.setAlpha(alpha);
  }

  @Override public void setColorFilter(@Nullable ColorFilter colorFilter) {
    mPaint.setColorFilter(colorFilter);
  }

  @Override public int getOpacity() {
    return PixelFormat.TRANSLUCENT;
  }

  @Override public int getIntrinsicWidth() {
    return (int) (8.38 * HEAD_RADIUS);
  }

  @Override public int getIntrinsicHeight() {
    return (int) (8.38 * HEAD_RADIUS);
  }

  public PointF getMiddlePoint() {
    return middlePoint;
  }

  public PointF getFishHeadPoint() {
    return fishHeadPoint;
  }

  public float getFrequency() {
    return frequency;
  }

  public void setFrequency(float frequency) {
    this.frequency = frequency;
  }

  public void setFishMainAngle(float angle) {
    fishMainAngle = angle;
  }
}
